package emailpoller;


import java.io.IOException;
import java.util.Properties;
import javax.mail.Folder;
import javax.mail.FolderClosedException;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.event.MessageCountAdapter;
import javax.mail.event.MessageCountEvent;
import javax.mail.internet.InternetAddress;
import com.sun.mail.imap.IMAPFolder;

public class SimpleEMailPoller {

    private String host;
    private String username;
    private String password;
    private String protocol;
    private String smtpServer;
    private int pollingFrequency;
    private boolean debug;
    private Properties props;
    private EMailPollerListener listener;
    
    public boolean polling = false;
    
    public SimpleEMailPoller(String username, String password) throws IOException {
        //This information should be stored in a config file.
        host = "imap.gmail.com";
        protocol = "imaps";
        smtpServer = "imap.gmail.com";
        pollingFrequency = 10000;
        debug = false;
        this.username = username;
        this.password = password;
        props = new Properties();
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.host", "smtp.gmail.com");
        props.put("mail.smtp.port", "587");

    }

    public void addListener(EMailPollerListener listener) {
        this.listener = listener;
    }
    
    public void startPolling() {

        if(polling) {
            return;
        }
        polling = true;
        
        System.out.println("Polling started...");
        final Session session = Session.getInstance(props);
        session.setDebug(debug);
        Folder inbox = null;
        Store store = null;

        /* This while loop will make sure the connection is reset if the server closes the connection.
         * Some MS Exchange Servers may be configured to close the connection if there is no activity on the inbox folder for a time period.
         */
        while (true) {

            try {
                System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
                System.out.println("New Connection Established");
                System.out.println("Host: " + host);
                System.out.println("Username: " + username);
                System.out.println("Protocol: " + protocol);
                System.out.println("Polling Frequency: " + pollingFrequency);
                System.out.println("Debug: " + debug);
                System.out.println("Smtp Server: " + smtpServer);
                System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
                System.out.println();

                if(listener != null) {
                    listener.gotMessage("Connection established at " + host + ": " + username);
                }
                
                store = session.getStore(protocol);
                store.connect(host, username, password);
                inbox = store.getFolder("INBOX");

                if (inbox == null) {
                    System.err.println("Cant find INBOX");
                    System.exit(1);
                }

                inbox.open(Folder.READ_ONLY);
                inbox.addMessageCountListener(new MessageCountAdapter() {

                    public void messagesAdded(MessageCountEvent ev) {

                        Message[] messages = ev.getMessages();
                        System.out.println("Got " + messages.length + " new messages");

                        for (int i = 0; i < messages.length; i++) {
                            try {
                                System.out.println("***********************************************************");
                                System.out.println("------------ Message " + (i + 1) + " ------------");
                                String from = (new InternetAddress(InternetAddress.toString(messages[i].getFrom())).getAddress());
                                String replyTo = InternetAddress.toString(messages[i].getReplyTo());
                                String to = InternetAddress.toString(messages[i].getRecipients(Message.RecipientType.TO));
                                String subject = messages[i].getSubject();
                                String sentDate = messages[i].getSentDate().toString();
                                String body = getText(messages[i]);

                                if(listener != null) {
                                    StringBuilder message = new StringBuilder();
                                    message.append("------ MESSAGE ------- \n");
                                    message.append(from + "\n");
                                    message.append(to + "\n");
                                    message.append(subject + "\n");
                                    message.append(sentDate + "\n");
                                    message.append(body + "\n");
                                    listener.gotMessage(message.toString());
                                }
                                
                                System.out.println("From: " + from);
                                System.out.println("Reply To: " + replyTo);
                                System.out.println("To: " + to);
                                System.out.println("Subject: " + subject);
                                System.out.println("Sent Date: " + sentDate);
                                System.out.println("Body: " + body);
                                System.out.println("***********************************************************");
                            } catch (MessagingException e) {
                                e.printStackTrace();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                });

// Check mail once in "pollingFrequency" MILLIseconds
                boolean supportsIdle = false;
                try {
                    if (inbox instanceof IMAPFolder) {
                        IMAPFolder f = (IMAPFolder) inbox;
                        f.idle();
                        supportsIdle = true;
                    }
                } catch (FolderClosedException fex) {
                    fex.printStackTrace();
                    throw fex;
                } catch (MessagingException mex) {
                    mex.printStackTrace();
                    supportsIdle = false;
                }
                for (;;) {
                    if (supportsIdle && inbox instanceof IMAPFolder) {
                        IMAPFolder f = (IMAPFolder) inbox;
                        f.idle();
                        System.out.println("IDLE done");
                    } else {
                        Thread.sleep(pollingFrequency); // sleep for pollingFrequency milliseconds
                        // This is to force the IMAP server to send us EXISTS notifications.
                        inbox.getMessageCount();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (inbox != null) {
                        inbox.close(false);
                    }
                    if (store != null) {
                        store.close();
                    }
                } catch (MessagingException e) {
                    e.printStackTrace();
                }
            }
        }//while
    }

    /**
     * Return the primary text content of the message.
     *
     * @param p
     * @return
     * @throws MessagingException
     * @throws IOException
     */
    private String getText(Part p) throws MessagingException, IOException {

        if (p.isMimeType("text/*")) {
            System.out.println("text/*");
            String s = (String) p.getContent();
            return s;
        }

        if (p.isMimeType("multipart/alternative")) {
            System.out.println("multipart/alternative");

// prefer html text over plain text
            Multipart mp = (Multipart) p.getContent();
            String text = "";

            for (int i = 0; i < mp.getCount(); i++) {
                Part bp = mp.getBodyPart(i);
                if (bp.isMimeType("text/plain")) {
                    System.out.println("text/plain");
                    if (text == null) {
                        text = getText(bp);
                    }
                    continue;
                } else if (bp.isMimeType("text/html")) {
                    System.out.println("text/html");
                    String s = getText(bp);
                    if (s != null) {
                        return s;
                    }
                } else {
                    return getText(bp);
                }
            }
            return text;
        } else if (p.isMimeType("multipart/*")) {
            System.out.println("multipart/*");
            Multipart mp = (Multipart) p.getContent();
            for (int i = 0; i < mp.getCount(); i++) {
                String s = getText(mp.getBodyPart(i));
                if (s != null) {
                    return s;
                }
            }
        }

        return null;
    }

    public static void main(String[] args) throws IOException {
    }
}
